#include "Component.h"

void Component::attributeElements(map<string, Primitive*> primitivesMap, map<string, Component*> componentsMap)
{
	vector<string> _primitiveString = getPrimitivesString();
	vector<string> _childrenString = getChildrenString();

	vector<Primitive*> primsStart;
	vector<Component*> childrenStart;

	for(size_t i = 0; i < _primitiveString.size(); i++)
		primsStart.push_back(primitivesMap[_primitiveString[i]]);

	for(size_t i = 0; i < _childrenString.size(); i++)
		childrenStart.push_back(componentsMap[_childrenString[i]]);

	setPrimitives(primsStart);
	setChildren(childrenStart);
}

void Component::constructTree(map<string, Primitive*> primitivesMap, map<string, Component*> componentsMap)
{
	vector<string> childIDsContainer = getChildrenString();
	vector<string> primitiveIDsContainer = getPrimitivesString();

	if(childIDsContainer.empty())
	{
		if(!primitiveIDsContainer.empty())
		{
			vector<Primitive*> primsToSet;
			for(size_t i = 0; i < primitiveIDsContainer.size(); i++)
				primsToSet.push_back(primitivesMap[primitiveIDsContainer[i]]);

			setPrimitives(primsToSet);
		}
		else
		{
			cout << "Componente " << getID() << " sem Primitivas nem Filhos!\n";
		}
	}
	else
	{
		if(!primitiveIDsContainer.empty())
		{
			vector<Primitive*> primsToSet;
			for(size_t i = 0; i < primitiveIDsContainer.size(); i++)
				primsToSet.push_back(primitivesMap[primitiveIDsContainer[i]]);

			setPrimitives(primsToSet);
		}
		else
		{
			cout << "Componente "<< getID() << " sem Primitivas!\n";
		}

		vector<Component*> compsToSet;
		for(size_t i = 0; i < childIDsContainer.size(); i++)
		{
			Component* c = componentsMap[childIDsContainer[i]];
			compsToSet.push_back(c);
			compsToSet[i]->constructTree(primitivesMap,componentsMap);
		}
		setChildren(compsToSet);
	}
}

void Component::runComponent(Texture* t, vector<Material*> m, bool change, char k)
{
	vector<Component*> compsToRun = getChildren();
	glPushMatrix();
		applyTransforms();

		if(getMaterialInherit())
			setMaterials(m);

		if(!getMaterialsColour().empty())
		{
			if(change)
				applyMaterialsColour(change, k);
			else
			{
				getMaterialsColour()[getCurrent()]->applyMaterial();
			}
		}
		else
			applyMaterials();

		if(getTextureInherit())
			renderPrimitives(t);
		else if(getNoTexture())
			renderPrimitives(NULL);
		else
			renderPrimitives(getTexture());

		for(size_t i = 0; i < compsToRun.size(); i++)
		{
			compsToRun[i]->runComponent(getTexture(), getMaterials(), change, k);
		}

	glPopMatrix();
}

void Component::applyTransforms()
{
	vector<Transformation*> _trans = getTransforms();
	for(size_t i = 0; i < _trans.size(); i++)
	{
		_trans[i]->applyTransform();
	}
}

void Component::applyMaterials()
{
	vector<Material*> _mats = getMaterials();
	for(size_t i = 0; i < _mats.size(); i++)
	{
		_mats[i]->applyMaterial();
	}
}

void Component::applyMaterialsColour(bool change, char k)
{
	vector<Material*> matsWithColour = getMaterialsColour();
	size_t size = matsWithColour.size();

	int curMat = getCurrent();
	
	if(change)
	{
		if(getKey() == k)
			curMat++;

		if(curMat == size)
			curMat = 0;

		setCurrent(curMat);
	}

	matsWithColour[curMat]->applyMaterial();
}

void Component::renderPrimitives(Texture* t)
{
	vector<Primitive*> _prims = getPrimitives();
	for(size_t i = 0; i < _prims.size(); i++)
	{
		if(t == NULL)
		{
			_prims[i]->setNoTex(true);
		}
		else
		{
			_prims[i]->setNoTex(false);

			if(_prims[i]->getTexInherit())
				_prims[i]->setTex(t);
		}
		_prims[i]->render();
	}
}

vector<char> Component::getKeys()
{
	vector<char> keys;
	vector<char> childKey;
	vector<Component*> childrenKeys = getChildren();

	if(getKey() != '\0')
		keys.push_back(getKey());

	for(size_t i = 0; i < childrenKeys.size(); i++)
	{
		childKey = childrenKeys[i]->getKeys();

		for(size_t i = 0; i < childKey.size(); i++)
			keys.push_back(childKey[i]);
	}
	return keys;
}